﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using System.Data.Entity;
using System.Data;
using System.Linq.Expressions;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using HLVControl.Grid;
using HLVControl.Grid.Data;
using System.Reflection;
using System.Data.Entity.Infrastructure;

namespace eService.BLL
{
    public interface IExecuteData<T> where T : class
    {
        IList<T> GetAll();
        T GetById(Object Id);
        bool Insert(T entity);
        bool Update(T oldEntity, T newEntity);
        bool Delete(T entity);
        bool Delete(Object id);
        List<T> FindAllBy<T>(Expression<Func<T, bool>> predicate) where T : class;
        T FindSingleBy<T>(Expression<Func<T, bool>> predicate) where T : class;
        DataTable ObjectQueryToDataTable();
        DataTable ToDataTable<T>(List<T> items);
        IEnumerable<T> GetAllEntity();
        //bool InitTreeListView(DataTable dt, String[] HeaderText, String[] Width, String[] MinWidth, Boolean[] VisibleCol, Boolean[] WordWrap, TreeListView treelistview);
        bool FillDataToTreeView(DataTable dt, TreeListView treelistview);
    }

    public class ExecuteData<T> : IExecuteData<T> where T : class
    {
        protected DbSet<T> DbSet { get; set; }
        protected DbContext dbEntities { get; set; }

        public ExecuteData(DbContext mydbEntities)
        {
            if (mydbEntities == null)
            {
                throw new ArgumentException("Null context");
            }
            this.dbEntities = mydbEntities;
            DbSet = mydbEntities.Set<T>();
        }

        public virtual IList<T> GetAll()
        {
            return DbSet.ToList();
        }
        public virtual T GetById(Object Id)
        {
            return DbSet.Find(Id);
        }
        public bool Insert(T entity)
        {
            var KQ = false;
            if (entity == null)
                throw new ArgumentNullException("Not found entity");
            T entity1 = dbEntities.Set<T>().Add(entity);
            if (entity1 != null)
            {
                KQ = true;
                dbEntities.SaveChanges();
            }
            return KQ;
        }
        public bool Update(T oldEntity, T newEntity)
        {
            var KQ = false;
            if (oldEntity == null)
                throw new ArgumentNullException("Not found entity");
            if (newEntity == null)
                throw new ArgumentNullException("Not found entity");
            if (newEntity != null)
            {
                dbEntities.Entry(newEntity).State = EntityState.Detached;
                dbEntities.Set<T>().Attach(oldEntity);
                dbEntities.Entry(oldEntity).State = EntityState.Modified;
                dbEntities.SaveChanges();
                KQ = true;
            }
            return KQ;
        }
        public bool Delete(T entity)
        {
            var KQ = false;
            if (entity == null)
                throw new ArgumentNullException("Not found entity");
            T entity1 = dbEntities.Set<T>().Remove(entity);
            if (entity1 != null)
            {
                KQ = true;
                dbEntities.SaveChanges();
            }
            return KQ;
        }
        public bool Delete(Object Id)
        {
            T entity = dbEntities.Entry(DbSet).Entity.Find(Id);
            return Delete(entity);
        }
        public List<T> FindAllBy<T>(Expression<Func<T, bool>> predicate) where T : class
        {
            if (predicate != null)
            {
                using (dbEntities)
                {
                    return dbEntities.Set<T>().AsQueryable<T>().ToList();
                }
            }
            else
                return null;
        }
        public T FindSingleBy<T>(Expression<Func<T, bool>> predicate) where T : class
        {
            if (predicate != null)
            {
                using (dbEntities)
                {
                    return dbEntities.Set<T>().Where(predicate).SingleOrDefault();
                }
            }
            return null;
        }
        public IEnumerable<T> GetAllEntity()
        {
            return (IEnumerable<T>)dbEntities.Set<T>().ToList();
        }
        public DataTable ToDataTable<T>(List<T> items)
        {
            //List<T> items = (List<T>)GetAllEntity();
            var tb = new DataTable();
            tb.TableName = typeof(T).Name;
            PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
            int j = 0;
            for (int i = 0; i < props.Length; i++)
            {
                j = i;
                if(j == 0)
                {
                    DataColumn colSTT = new DataColumn("colSTT");
                    tb.Columns.Add(colSTT);
                }
            }
            foreach (PropertyInfo prop in props)
            {
                Type t = GetCoreType(prop.PropertyType);
                tb.Columns.Add(prop.Name, t);
            }
            j = 0;
            foreach (T item in items)
            {
                var values = new object[props.Length + 1];
                values[0] = j + 1;
                for (int i = 0; i < props.Length; i++)
                {
                    values[i+1] = props[i].GetValue(item, null);
                }
                tb.Rows.Add(values);
                j++;
            }
            return tb;
        }
        private static bool IsNullable(Type t)
        {
            return !t.IsValueType || (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>));
        }
        private static Type GetCoreType(Type t)
        {
            if (t != null && IsNullable(t))
            {
                if (!t.IsValueType)
                {
                    return t;
                }
                else
                {
                    return Nullable.GetUnderlyingType(t);
                }
            }
            else
            {
                return t;
            }
        }

        public DataTable ObjectQueryToDataTable()
        {
            IEnumerable<T> GetAllData = GetAllEntity();
            DataTable dtReturn = new DataTable();
            PropertyInfo[] objProps = null;
            if (GetAllData == null)
                return dtReturn;
            foreach (T objRec in GetAllData)
            {
                if (objProps == null)
                {
                    objProps = ((Type)objRec.GetType()).GetProperties();
                    foreach (PropertyInfo objpi in objProps)
                    {
                        Type colType = objpi.PropertyType;
                        if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                            colType = colType.GetGenericArguments()[0];
                        dtReturn.Columns.Add(new DataColumn(objpi.Name, colType));
                    }
                }
                DataRow dr = dtReturn.NewRow();
                foreach (PropertyInfo pi in objProps)
                    dr[pi.Name] = pi.GetValue(objRec, null) == null ? DBNull.Value : pi.GetValue(objRec, null);
                dtReturn.Rows.Add(dr);
            }
            return dtReturn;
        }
        //public bool InitTreeListView(DataTable dt, String[] HeaderText, String[] Width, String[] MinWidth, Boolean[] VisibleCol, Boolean[] WordWrap, TreeListView treelistview)
        //{
        //    treelistview.Columns.Clear();
        //    TreeListColumn[] ArrayCol = new TreeListColumn[dt.Columns.Count];
        //    for (int i = 0; i < ArrayCol.Length; i++)
        //    {
        //        TreeListColumn col = new TreeListColumn();
        //        col.Name = "col" + dt.Columns[i].ColumnName.ToString();
        //        col.Text = HeaderText[i].ToString();
        //        col.Visible = VisibleCol[i];
        //        col.Width = Int32.Parse(Width[i].ToString());
        //        col.WordWrap = WordWrap[i];
        //        col.MinWidth = Int32.Parse(MinWidth[i].ToString());
        //        treelistview.Columns.Add(col);
        //    }
        //    treelistview.Refresh();
        //    if (treelistview.Columns.Count == dt.Columns.Count)
        //        return true;
        //    else
        //        return false;
        //}

        public bool FillDataToTreeView(DataTable dt, TreeListView treelistview)
        {
            if(treelistview.Rows.Count >= 0)
                treelistview.Rows.Clear();
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                TreeListRow row = treelistview.CreateRow();
                for (int j = 0; j < dt.Columns.Count; j++)
                {
                    row.Cells.Add(new TreeListCell(dt.Rows[i][j].ToString()));
                }
                if (row != null)
                    treelistview.Rows.Add(row);
                else
                    treelistview.Remove(row);
            }
            treelistview.Refresh();
            return true;
        }
        
    }
}
